package com.jf.yytgd.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.jf.yytgd.converter.CombinedConverter;
import com.jf.yytgd.converter.CommentConverter;
import com.jf.yytgd.converter.DiaryConverter;
import com.jf.yytgd.converter.PageConverter;
import com.jf.yytgd.dao.CommentMapper;
import com.jf.yytgd.dao.DiaryMapper;
import com.jf.yytgd.dao.UserMapper;
import com.jf.yytgd.entity.bean.Comment;
import com.jf.yytgd.entity.bean.Diary;
import com.jf.yytgd.entity.bean.User;
import com.jf.yytgd.entity.dto.combined.ChildCommentUserDTO;
import com.jf.yytgd.entity.dto.combined.CommentUserDTO;
import com.jf.yytgd.entity.dto.combined.DiaryUserBarDTO;
import com.jf.yytgd.entity.dto.combined.DiaryUserDTO;
import com.jf.yytgd.entity.dto.comment.CommentCreateDTO;
import com.jf.yytgd.entity.dto.diary.DiaryPublishDTO;
import com.jf.yytgd.entity.dto.like.LikeDTO;
import com.jf.yytgd.entity.dto.like.LikeExistDTO;
import com.jf.yytgd.service.DiaryService;
import com.jf.yytgd.service.LikeService;
import jakarta.annotation.Resource;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Isolation;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * Created with IntelliJ IDEA
 * Description: 日记服务层实现
 * User:22954
 * Date:2025-01-13
 * Time:12:58
 */
@Transactional(isolation = Isolation.READ_COMMITTED)
@Service
public class DiaryServiceImpl extends ServiceImpl<DiaryMapper, Diary> implements DiaryService {
    @Resource
    private DiaryMapper diaryMapper;
    @Resource
    private UserMapper userMapper;
    @Resource
    private LikeService likeService;
    @Resource
    private CommentMapper commentMapper;

    /**
     * 浏览日记详情
     * 根据日记ID获取日记详情，并增加日记的浏览量同时更新数据库
     * 根据日记的用户ID获取用户信息，最后将日记和用户信息组合成一个DTO返回
     *
     * @param diaryId 日记ID，用于查询特定的日记信息
     * @return 返回一个包含日记和用户信息的DTO对象
     */
    @Override
    public DiaryUserDTO browse(Integer diaryId) {
        Diary diary = diaryMapper.getDiaryById(diaryId);
        diary.setViews(diary.getViews() + 1);
        diaryMapper.updateById(diary);
        User user = userMapper.selectById(diary.getUserId());
        return CombinedConverter.INSTANCE.toDiaryUserDTO(diary, user);
    }

    @Override
    public Page<DiaryUserBarDTO> barPage(Integer pageNo, Integer pageSize, String search, String order) {
        Page<Diary> page = new Page<>(pageNo, pageSize);
        QueryWrapper<Diary> queryWrapper = new QueryWrapper<>();
        if (StringUtils.hasText(search)) {
            queryWrapper.like("title", search);
        }
        if (StringUtils.hasText(order)) {
            queryWrapper.orderByDesc(order);
        }
        return getDiaryUserBarDTOPage(page, queryWrapper);
    }

    @Override
    public Page<DiaryUserBarDTO> userBarPage(Integer pageNo, Integer pageSize, Integer userId) {
        Page<Diary> page = new Page<>(pageNo, pageSize);
        QueryWrapper<Diary> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("user_id", userId);
        return getDiaryUserBarDTOPage(page, queryWrapper);
    }

    private Page<DiaryUserBarDTO> getDiaryUserBarDTOPage(Page<Diary> page, QueryWrapper<Diary> queryWrapper) {
        page = page(page, queryWrapper);
        List<Diary> records = page.getRecords();
        List<Integer> userIds = records.stream().map(Diary::getUserId).collect(Collectors.toList());
        List<User> users = userMapper.selectByIds(userIds);
        Map<Integer, User> userMap = users.stream().collect(Collectors.toMap(User::getId, user -> user));
        List<DiaryUserBarDTO> dtoRecords = new ArrayList<>();
        for (Diary diary : records) {
            DiaryUserBarDTO diaryUserBarDTO = CombinedConverter.INSTANCE.toDiaryUserBarDTO(diary, userMap.get(diary.getUserId()));
            dtoRecords.add(diaryUserBarDTO);
        }
        return PageConverter.INSTANCE.convert(page, dtoRecords);
    }

    @Override
    public void like(LikeDTO likeDTO) {
        likeDTO.setRelatedType("Diary");
        boolean isLike = likeService.like(likeDTO);
        Diary diary = diaryMapper.getDiaryById(likeDTO.getRelatedId());
        if (isLike) {
            diary.setLikes(diary.getLikes() + 1);
        } else {
            diary.setLikes(diary.getLikes() - 1);
        }
        diaryMapper.updateById(diary);
    }

    @Override
    public boolean isLike(LikeExistDTO likeDTO) {
        likeDTO.setRelatedType("Diary");
        return likeService.isLike(likeDTO);
    }

    @Override
    public void publish(DiaryPublishDTO diaryDTO) {
        diaryMapper.insertWithBlob(DiaryConverter.INSTANCE.toBean(diaryDTO));
    }

    @Override
    public void comment(CommentCreateDTO commentDTO) {
        commentDTO.setRelatedType("Diary");
        Comment comment = CommentConverter.INSTANCE.toBean(commentDTO);
        commentMapper.insert(comment);
        Diary diary = diaryMapper.selectById(comment.getRelatedId());
        diary.setComments(diary.getComments() + 1);
        diaryMapper.updateById(diary);
    }

    @Override
    public List<CommentUserDTO> listComment(Integer diaryId) {
        QueryWrapper<Comment> commentQueryWrapper = new QueryWrapper<>();
        commentQueryWrapper.eq("related_type", "Diary")
                .eq("related_id", diaryId);
        List<Comment> comments = commentMapper.selectList(commentQueryWrapper);
        List<CommentUserDTO> commentUserDTOs = new ArrayList<>();
        for (Comment comment : comments) {
            User father = userMapper.selectById(comment.getUserId());
            CommentUserDTO commentUserDTO = CombinedConverter.INSTANCE.toCommentUserDTO(comment, father);
            commentUserDTOs.add(commentUserDTO);
            // 添加子评论
            List<Comment> childrenList = getCommentChildren(comment);
            if (childrenList == null) {
                continue;
            }
            List<Integer> userIds = childrenList.stream().map(Comment::getUserId).toList();
            List<User> users = userMapper.selectByIdsWithDuplicate(userIds);
            List<ChildCommentUserDTO> childrenDtoList = new ArrayList<>();
            for (int i = 0; i < childrenList.size(); i++) {
                ChildCommentUserDTO child = CombinedConverter.INSTANCE.toChildCommentUserDTO(childrenList.get(i), users.get(i), father);
                childrenDtoList.add(child);
            }
            commentUserDTO.setChildren(childrenDtoList);
        }
        return commentUserDTOs;
    }

    private List<Comment> getCommentChildren(List<Comment> comments, List<Comment> children) {
        List<Integer> commentIds = new ArrayList<>();
        for (Comment comment : comments) {
            if (comment.getComments() > 0) {
                commentIds.add(comment.getId());
            }
        }
        QueryWrapper<Comment> queryWrapper = new QueryWrapper<Comment>().eq("related_type", "Comment");
        if (!commentIds.isEmpty()) {
            queryWrapper.in("related_id", commentIds);
            List<Comment> temp = commentMapper.selectList(queryWrapper);
            if (children == null)
                children = new ArrayList<>();
            children.addAll(temp);
            return getCommentChildren(temp, children);
        }
        return children;
    }
    private List<Comment> getCommentChildren(Comment comment) {
        List<Comment> comments = new ArrayList<>();
        comments.add(comment);

        return getCommentChildren(comments, null);
    }
}
